<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tomcat负载均衡与会话保持配置指南</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.8;
            color: #333;
            background-color: #f9fafb;
        }
        h1, h2, h3, h4 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
            margin-top: 1.5em;
            margin-bottom: 0.8em;
        }
        .hero {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
            color: white;
            position: relative;
            overflow: hidden;
        }
        .hero-content {
            position: relative;
            z-index: 2;
        }
        .hero::before {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: url('');
            opacity: 0.4;
        }
        .card {
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
            border-radius: 0.5rem;
            overflow: hidden;
        }
        .card:hover {
            transform: translateY(-4px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        .code-block {
            background-color: #1e293b;
            color: #f8fafc;
            border-radius: 0.375rem;
            position: relative;
        }
        .code-header {
            background-color: #0f172a;
            padding: 0.5rem 1rem;
            border-top-left-radius: 0.375rem;
            border-top-right-radius: 0.375rem;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        .code-copy {
            cursor: pointer;
            color: #94a3b8;
            transition: color 0.2s;
        }
        .code-copy:hover {
            color: #e2e8f0;
        }
        .code-content {
            padding: 1rem;
            overflow-x: auto;
        }
        .highlight {
            position: relative;
        }
        .highlight::before {
            content: "";
            position: absolute;
            left: -4px;
            top: 0;
            height: 100%;
            width: 4px;
            background: linear-gradient(to bottom, #4f46e5, #7c3aed);
            border-radius: 2px;
        }
        .mermaid-chart {
            background-color: white;
            border-radius: 0.5rem;
            padding: 1.5rem;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
        }
        .footer {
            background-color: #1e293b;
            color: #f8fafc;
        }
        .footer a:hover {
            color: #818cf8;
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero py-20 px-4 md:py-32">
        <div class="container mx-auto max-w-6xl hero-content">
            <div class="flex flex-col md:flex-row items-center">
                <div class="md:w-1/2 mb-10 md:mb-0">
                    <h1 class="text-4xl md:text-5xl font-bold mb-6">Tomcat负载均衡与会话保持</h1>
                    <p class="text-xl md:text-2xl font-light max-w-lg mb-8">优化Web应用的可用性、扩展性和用户体验</p>
                    <div class="flex space-x-4">
                        <div class="flex items-center bg-white bg-opacity-20 px-4 py-2 rounded-full">
                            <i class="fas fa-server mr-2"></i>
                            <span>高可用性</span>
                        </div>
                        <div class="flex items-center bg-white bg-opacity-20 px-4 py-2 rounded-full">
                            <i class="fas fa-expand-arrows-alt mr-2"></i>
                            <span>可扩展性</span>
                        </div>
                        <div class="flex items-center bg-white bg-opacity-20 px-4 py-2 rounded-full">
                            <i class="fas fa-user-shield mr-2"></i>
                            <span>一致性体验</span>
                        </div>
                    </div>
                </div>
                <div class="md:w-1/2">
                    <div class="bg-white bg-opacity-20 p-6 rounded-xl backdrop-blur-sm border border-white border-opacity-20">
                        <div class="mermaid-chart">
                            <div class="mermaid">
                                graph TD
                                    A[客户端] --> B[负载均衡器]
                                    B --> C[Tomcat 实例1]
                                    B --> D[Tomcat 实例2]
                                    B --> E[Tomcat 实例3]
                                    C --> F[会话数据]
                                    D --> F
                                    E --> F
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-6xl px-4 py-12">
        <!-- Introduction -->
        <section class="mb-16">
            <div class="prose prose-lg max-w-full">
                <p class="text-gray-600">在 Tomcat 中配置负载均衡和会话保持（Session Persistence）是为了确保用户请求能够均匀地分布到不同的服务器上，并在集群环境下保持用户会话的连续性。负载均衡可以提高应用的可用性和扩展性，而会话保持则保证用户体验的一致性。</p>
            </div>
        </section>

        <!-- Section 1 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-balance-scale text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">1. Tomcat 负载均衡概述</h2>
            </div>
            
            <div class="prose prose-lg max-w-full mb-8">
                <p>负载均衡主要用于将客户端请求分配到多个服务器（Tomcat 实例）上，从而分散负载，避免单点故障。常见的负载均衡策略包括：</p>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6 mb-8">
                <div class="card bg-white p-6 hover:border-indigo-500 border border-gray-200">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-redo text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">轮询 (Round Robin)</h3>
                    </div>
                    <p class="text-gray-600">按顺序将请求分配给每台服务器，实现简单均衡分配</p>
                </div>
                
                <div class="card bg-white p-6 hover:border-indigo-500 border border-gray-200">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-link text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">最少连接 (Least Connections)</h3>
                    </div>
                    <p class="text-gray-600">将请求分配给当前连接数最少的服务器，适用于长连接场景</p>
                </div>
                
                <div class="card bg-white p-6 hover:border-indigo-500 border border-gray-200">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-weight-hanging text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">加权轮询 (Weighted Round Robin)</h3>
                    </div>
                    <p class="text-gray-600">为不同服务器分配不同权重，适合服务器性能不均的场景</p>
                </div>
            </div>
        </section>

        <!-- Section 2 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-cogs text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">2. 负载均衡的实现方式</h2>
            </div>
            
            <div class="prose prose-lg max-w-full mb-8">
                <p>在 Tomcat 中，负载均衡通常需要借助外部负载均衡器或代理服务器来实现。以下是几种常见的实现方式：</p>
            </div>

            <!-- Subsection 2.1 -->
            <div class="highlight pl-6 mb-12">
                <h3 class="text-2xl font-semibold mb-6">2.1 使用 Apache HTTP Server（mod_jk 或 mod_proxy）</h3>
                
                <div class="prose prose-lg max-w-full mb-6">
                    <p>Apache HTTP Server 是常用的 Web 服务器之一，支持多种负载均衡模块，如 <code>mod_jk</code> 和 <code>mod_proxy</code>，可以实现 HTTP 请求的负载均衡和会话保持。</p>
                </div>
                
                <div class="grid md:grid-cols-2 gap-6">
                    <!-- mod_jk Card -->
                    <div class="card bg-white">
                        <div class="p-6">
                            <div class="flex items-center mb-4">
                                <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                                    <i class="fas fa-code text-indigo-600"></i>
                                </div>
                                <h4 class="text-xl font-semibold">mod_jk</h4>
                            </div>
                            <p class="text-gray-600 mb-4">一个 Apache HTTP Server 和 Tomcat 之间的连接器，使用 Apache JServ Protocol (AJP) 协议进行通信。支持细粒度的负载均衡配置和会话保持。</p>
                            
                            <div class="mb-4">
                                <h5 class="font-semibold text-gray-700 mb-2">配置步骤：</h5>
                                <ol class="list-decimal pl-5 text-gray-600 space-y-2">
                                    <li>安装 <code>mod_jk</code> 模块</li>
                                    <li>配置 <code>workers.properties</code></li>
                                    <li>修改 Apache 配置文件 (<code>httpd.conf</code>)</li>
                                </ol>
                            </div>
                        </div>
                        
                        <div class="code-block">
                            <div class="code-header">
                                <span>workers.properties</span>
                                <button class="code-copy"><i class="far fa-copy"></i></button>
                            </div>
                            <div class="code-content">
                                <pre><code class="language-properties">worker.list=loadbalancer

# 定义 Tomcat 实例 worker1
worker.worker1.type=ajp13
worker.worker1.host=tomcat1.example.com
worker.worker1.port=8009

# 定义 Tomcat 实例 worker2
worker.worker2.type=ajp13
worker.worker2.host=tomcat2.example.com
worker.worker2.port=8009

# 定义负载均衡器
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=worker1,worker2
worker.loadbalancer.sticky_session=True</code></pre>
                            </div>
                        </div>
                    </div>
                    
                    <!-- mod_proxy Card -->
                    <div class="card bg-white">
                        <div class="p-6">
                            <div class="flex items-center mb-4">
                                <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                                    <i class="fas fa-exchange-alt text-indigo-600"></i>
                                </div>
                                <h4 class="text-xl font-semibold">mod_proxy</h4>
                            </div>
                            <p class="text-gray-600 mb-4">一个 Apache HTTP Server 的模块，支持正向代理和反向代理功能。可以通过 HTTP、HTTPS 协议转发请求，适用于简单的负载均衡场景。</p>
                            
                            <div class="mb-4">
                                <h5 class="font-semibold text-gray-700 mb-2">配置步骤：</h5>
                                <ol class="list-decimal pl-5 text-gray-600 space-y-2">
                                    <li>启用 <code>mod_proxy</code> 和 <code>mod_proxy_balancer</code> 模块</li>
                                    <li>配置反向代理和负载均衡</li>
                                </ol>
                            </div>
                        </div>
                        
                        <div class="code-block">
                            <div class="code-header">
                                <span>httpd.conf</span>
                                <button class="code-copy"><i class="far fa-copy"></i></button>
                            </div>
                            <div class="code-content">
                                <pre><code class="language-apacheconf">&lt;Proxy "balancer://mycluster"&gt;
    BalancerMember http://tomcat1.example.com:8080 route=worker1
    BalancerMember http://tomcat2.example.com:8080 route=worker2
    ProxySet stickysession=JSESSIONID
&lt;/Proxy&gt;

ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Subsection 2.2 -->
            <div class="highlight pl-6 mb-12">
                <h3 class="text-2xl font-semibold mb-6">2.2 使用 Nginx 作为负载均衡器</h3>
                
                <div class="prose prose-lg max-w-full mb-6">
                    <p>Nginx 是一个高性能的反向代理服务器，支持 HTTP 和 TCP 负载均衡，可以与 Tomcat 集成实现负载均衡和会话保持。</p>
                </div>
                
                <div class="card bg-white mb-6">
                    <div class="p-6">
                        <div class="flex items-center mb-4">
                            <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                                <i class="fab fa-nginx text-indigo-600"></i>
                            </div>
                            <h4 class="text-xl font-semibold">Nginx 配置</h4>
                        </div>
                        
                        <div class="mb-4">
                            <h5 class="font-semibold text-gray-700 mb-2">配置步骤：</h5>
                            <ol class="list-decimal pl-5 text-gray-600 space-y-2">
                                <li>安装 Nginx</li>
                                <li>配置 Nginx 负载均衡</li>
                            </ol>
                        </div>
                    </div>
                    
                    <div class="code-block">
                        <div class="code-header">
                            <span>nginx.conf</span>
                            <button class="code-copy"><i class="far fa-copy"></i></button>
                        </div>
                        <div class="code-content">
                            <pre><code class="language-nginx">upstream mycluster {
    server tomcat1.example.com:8080;
    server tomcat2.example.com:8080;
    ip_hash;  # 基于 IP 的会话保持策略
}

server {
    listen 80;
    server_name www.example.com;

    location / {
        proxy_pass http://mycluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="prose prose-lg max-w-full">
                    <p><code>ip_hash</code>：通过 IP 地址哈希的方式实现会话保持，确保来自同一客户端的请求始终被分配到同一台 Tomcat 服务器。</p>
                </div>
            </div>

            <!-- Subsection 2.3 -->
            <div class="highlight pl-6">
                <h3 class="text-2xl font-semibold mb-6">2.3 使用 F5 或其他硬件负载均衡设备</h3>
                
                <div class="prose prose-lg max-w-full">
                    <p>硬件负载均衡器，如 F5、Citrix ADC，可以提供高性能的负载均衡解决方案，并支持会话保持、SSL 卸载等高级功能。</p>
                </div>
            </div>
        </section>

        <!-- Section 3 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-user-shield text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">3. 会话保持的实现方式</h2>
            </div>
            
            <div class="prose prose-lg max-w-full mb-8">
                <p>会话保持用于在负载均衡环境下确保同一用户的所有请求都路由到同一台服务器上。Tomcat 提供了多种会话保持机制：</p>
            </div>
            
            <div class="grid md:grid-cols-2 gap-6 mb-8">
                <div class="card bg-white p-6">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-cookie text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">3.1 基于 Cookie 的会话保持</h3>
                    </div>
                    <p class="text-gray-600 mb-4">默认情况下，Tomcat 使用基于 Cookie 的会话保持机制。负载均衡器会将 <code>JSESSIONID</code>（会话 ID）附加在 Cookie 中，并使用该 ID 路由后续请求。</p>
                    <p class="text-gray-600"><strong>配置方法：</strong> 在负载均衡器（如 Apache、Nginx）中启用 Cookie 识别和路由功能。例如，使用 <code>ProxySet stickysession=JSESSIONID</code>。</p>
                </div>
                
                <div class="card bg-white p-6">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-link text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">3.2 基于 URL 重写的会话保持</h3>
                    </div>
                    <p class="text-gray-600 mb-4">当客户端不支持 Cookie 时，Tomcat 会使用 URL 重写（URL Rewriting）方式，将 <code>JSESSIONID</code> 附加到 URL 中。</p>
                    <p class="text-gray-600"><strong>配置方法：</strong> 无需额外配置，Tomcat 会自动处理。</p>
                </div>
                
                <div class="card bg-white p-6">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-network-wired text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">3.3 基于 IP 的会话保持</h3>
                    </div>
                    <p class="text-gray-600 mb-4">负载均衡器可以根据客户端 IP 地址进行会话保持，确保来自相同 IP 地址的请求始终路由到同一台服务器。</p>
                    <p class="text-gray-600"><strong>配置方法：</strong> 在 Nginx 中，可以使用 <code>ip_hash</code> 指令；在 Apache 中，可以使用 <code>mod_jk</code> 的 <code>sticky_session</code> 设置。</p>
                </div>
                
                <div class="card bg-white p-6">
                    <div class="flex items-center mb-4">
                        <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-3">
                            <i class="fas fa-copy text-indigo-600"></i>
                        </div>
                        <h3 class="text-xl font-semibold">3.4 会话复制（Session Replication）</h3>
                    </div>
                    <p class="text-gray-600 mb-4">会话复制是在集群中共享会话数据的机制，确保每个 Tomcat 实例都可以访问相同的会话数据。Tomcat 支持基于 <code>DeltaManager</code> 和 <code>BackupManager</code> 的会话复制。</p>
                    <p class="text-gray-600"><strong>配置方法：</strong> 在 <code>conf/server.xml</code> 文件的 <code>&lt;Cluster&gt;</code> 元素中配置会话复制：</p>
                    
                    <div class="code-block mt-4">
                        <div class="code-header">
                            <span>server.xml</span>
                            <button class="code-copy"><i class="far fa-copy"></i></button>
                        </div>
                        <div class="code-content">
                            <pre><code class="language-xml">&lt;Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"&gt;
    &lt;Manager className="org.apache.catalina.ha.session.DeltaManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true"/&gt;
    &lt;Channel className="org.apache.catalina.tribes.group.GroupChannel"&gt;
        &lt;!-- 集群通信配置 --&gt;
    &lt;/Channel&gt;
&lt;/Cluster&gt;</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Summary Section -->
        <section class="bg-indigo-50 rounded-xl p-8 mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-lightbulb text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-2xl font-bold">关键点总结</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-6">
                <div>
                    <h3 class="text-xl font-semibold mb-4">负载均衡</h3>
                    <ul class="list-disc pl-5 space-y-2 text-gray-700">
                        <li>Apache HTTP Server (<code>mod_jk</code>, <code>mod_proxy</code>)</li>
                        <li>Nginx 反向代理</li>
                        <li>F5 等硬件负载均衡器</li>
                        <li>支持多种调度算法：轮询、最少连接、加权轮询等</li>
                    </ul>
                </div>
                
                <div>
                    <h3 class="text-xl font-semibold mb-4">会话保持</h3>
                    <ul class="list-disc pl-5 space-y-2 text-gray-700">
                        <li>基于 Cookie (<code>JSESSIONID</code>)</li>
                        <li>基于 URL 重写</li>
                        <li>基于 IP 哈希</li>
                        <li>会话复制 (Session Replication)</li>
                    </ul>
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="footer py-8">
        <div class="container mx-auto max-w-6xl px-4 text-center">
            <div class="flex flex-col items-center">
                <div class="text-lg font-medium mb-2">技术小馆</div>
                <a href="http://www.yuque.com/jtostring" class="text-indigo-300 hover:text-white transition-colors">http://www.yuque.com/jtostring</a>
            </div>
        </div>
    </footer>

    <!-- Scripts -->
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: false,
                htmlLabels: true,
                curve: 'basis'
            }
        });

        // Copy code functionality
        document.querySelectorAll('.code-copy').forEach(button => {
            button.addEventListener('click', () => {
                const codeBlock = button.closest('.code-block');
                const codeContent = codeBlock.querySelector('.code-content pre code');
                const textToCopy = codeContent.textContent;
                
                navigator.clipboard.writeText(textToCopy).then(() => {
                    button.innerHTML = '<i class="fas fa-check"></i>';
                    setTimeout(() => {
                        button.innerHTML = '<i class="far fa-copy"></i>';
                    }, 2000);
                });
            });
        });

        // Smooth scrolling for anchor links
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>